package com.boss.thirteen.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.boss.common.entity.WfActionDTO;
import com.boss.common.enums.ActionTypeEnum;
import com.boss.common.service.ICommonService;
import com.boss.common.util.DateUtils;
import com.boss.framework.exception.AppRuntimeException;
import com.boss.salary.constant.SystemDictConstant;
import com.boss.salary.dao.IPayMentLockDao;
import com.boss.salary.entity.AgencySalaryPayment;
import com.boss.salary.entity.MakeSalaryData;
import com.boss.salary.entity.SalaryPaymentRequisitionBack;
import com.boss.salary.service.IRedisService;
import com.boss.sys.ca.user.dto.UserDTO;
import com.boss.sys.utils.SysUtils;
import com.boss.thirteen.dao.IThirteenAgencyVerifyDao;
import com.boss.thirteen.dao.IThirteenGenerateSalaryDataDao;
import com.boss.thirteen.dao.IThirteenSalaryPaymentDao;
import com.boss.thirteen.entity.ThirteenAgencyVerify;
import com.boss.thirteen.service.ISalaryThirteenWorkFlowService;
import com.boss.thirteen.service.IThirteenGenerateSalaryDataService;
import com.boss.thirteen.service.IThirteenPaymentAsyncService;
import io.seata.spring.annotation.GlobalTransactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ThirteenGenerateSalaryDataServiceImpl implements IThirteenGenerateSalaryDataService {

    private static final Logger logger = LoggerFactory.getLogger(ThirteenGenerateSalaryDataServiceImpl.class);

    @Autowired
    private IThirteenGenerateSalaryDataDao iGenerateSalaryDataDao;

    @Autowired
    private IThirteenSalaryPaymentDao iAgencySalaryPaymentDao;

    @Autowired
    private ICommonService iCommonService;

    @Autowired
    private IThirteenAgencyVerifyDao agencyVerifyDao;

    @Autowired
    private ISalaryThirteenWorkFlowService iSalaryWorkFlowService;

    @Autowired
    private IPayMentLockDao iPayMentLockDao;

    @Autowired
    private ICommonService commonService;

    @Autowired
    private IThirteenPaymentAsyncService paymentAsyncService;
    @Autowired
    private IRedisService redisService;

    @Override
    public boolean getBankDataStatus(List<String> agencyIds) {
        List<ThirteenAgencyVerify> list = iGenerateSalaryDataDao.getBankDataStatus(agencyIds);
        Set<Integer> set = list.stream().map(ThirteenAgencyVerify::getIsBankDataCreated).collect(Collectors.toSet());
        boolean status = false;
        for (Integer i : set) {
            if (i == 1) {
                status = true;
                break;
            }
        }
        return status;
    }

    /**
     * 撤销支付申请
     * @param tokenid
     * @param makeSalaryData 要撤销的单位id
     */
    @Override
    @GlobalTransactional(timeoutMills=300000)//@Transactional(rollbackFor = Exception.class)
    public void revokeSalaryData(String tokenid,MakeSalaryData makeSalaryData,UserDTO userDto) {
        // 获取已生成的工资数据
        List<Map<String, Object>> list = iGenerateSalaryDataDao.getRevokePayBackData(makeSalaryData.getAgencyIds());

        if (list.size()> 0)  {
            // 获取所有支付id
            List<String> payId = list.stream().filter(map-> !StringUtils.isEmpty(map.get("pay_id"))).collect(Collectors.toList())
                    .stream().map(map->map.get("pay_id").toString()).collect(Collectors.toList());
            // 调用支付预算平台，取消支付申请
            Map<String, String> result = iCommonService.nullifyPayMent(payId, tokenid);
            JSONObject jsonObject = JSONObject.parseObject(result.get("result"));
            String rscode = jsonObject.getString("rscode");
            if ("200".equals(rscode)) {
                logger.info("==========作废支付申请成功================");
                if (!StringUtils.isEmpty(list) && list.size() > 0) {
                    for (Map<String, Object> map : list) {
                        String id = map.get("id").toString();//peyment表id
                        String agencyId = map.get("agency_id").toString();

                        if(StringUtils.isEmpty(agencyId)){
                            continue;
                        }
                        // 修改审核状态表生成工资状态为未生成
                        iGenerateSalaryDataDao.updatePayData(agencyId, String.valueOf(SystemDictConstant.IS_FALSE));
                        logger.info("单位："+agencyId+"==========修改审核表完成================");
                        // 删除支付回单表数据
                        SalaryPaymentRequisitionBack salaryPaymentRequisitionBack = new SalaryPaymentRequisitionBack();
                        salaryPaymentRequisitionBack.setId(id);
                        iGenerateSalaryDataDao.deletePayBackData(salaryPaymentRequisitionBack);



                    }
                        // 获取单位审核状态信息
                        List<ThirteenAgencyVerify> agencyVerify1 = agencyVerifyDao.getAgencyVerifyByAgencyIds(makeSalaryData.getAgencyIds());
                        // 单位上报录入流程
                        WfActionDTO<List<ThirteenAgencyVerify>> wfActionDTO = new WfActionDTO();
                        wfActionDTO.setMenuguid(makeSalaryData.getMenuid());
                        // 撤销
                        wfActionDTO.setActionType(ActionTypeEnum.WF_RECALL.getActionTypeCode());
                        wfActionDTO.setBizDatas(agencyVerify1);
                        wfActionDTO.setBizKeyName("bizKey");
                        wfActionDTO.setMessage("");
                        iSalaryWorkFlowService.doSalaryFlowList(userDto, wfActionDTO,null);
                        agencyVerifyDao.batchUpdateAgencyVerifypayStatus(agencyVerify1);
                        logger.info("==== 工作流生成银行数据撤销完毕End  ===");

                }
            } else {
                throw new AppRuntimeException(jsonObject.getString("result"));
            }
        }
    }

    /**
     * 获取支付回单数据
     * @param queryParam
     * @return
     * @throws IOException
     */
    @Override
    public List<SalaryPaymentRequisitionBack> getPayBackData(Map<String, Object> queryParam) throws IOException {
        List<SalaryPaymentRequisitionBack> list = iGenerateSalaryDataDao.getPayBackData(queryParam);
        String year=String.valueOf(Calendar.getInstance().get(Calendar.YEAR));

        if (!StringUtils.isEmpty(list) && list.size() > 0) {
            // 获取所有指标id
            List<String> bgtId = list.stream().filter(bean-> !StringUtils.isEmpty(bean.getBgtId())).collect(Collectors.toList())
                    .stream().map(SalaryPaymentRequisitionBack::getBgtId).collect(Collectors.toList());
            Map<String, Object> query = new HashMap<>(1);
            if (!StringUtils.isEmpty(bgtId) && bgtId.size() > 0) {
                query.put("condition", SysUtils.inSql("sum_id", bgtId));
                query.put("fiscal_year", year);//获取业务年份
                query.put("mof_div_code",queryParam.get("mof_div_code"));
                list = getBgtData(list, query);
            }
        }
        return list;
    }

    /**
     * 获取指标数据
     * @return
     */
    private List<SalaryPaymentRequisitionBack> getBgtData(List<SalaryPaymentRequisitionBack> list, Map<String, Object> query) throws IOException {
        // 获取所有的指标
        JSONArray jsonArray = iCommonService.getPayMent(query,false);
        if (!StringUtils.isEmpty(jsonArray) && jsonArray.size() > 0) {
            // 根据选择的指标id，获取具体内容
            for (SalaryPaymentRequisitionBack salaryPaymentRequisitionBack : list) {
                if (!StringUtils.isEmpty(salaryPaymentRequisitionBack.getBgtId())) {
                    // 如果有挂接的指标id，则获取指标信息
                    String bgtId = salaryPaymentRequisitionBack.getBgtId();
                    if (!StringUtils.isEmpty(bgtId)) {
                        for (int i = 0; i < jsonArray.size(); i++) {
                            JSONObject jsonObject = jsonArray.getJSONObject(i);
                            String sumId = jsonObject.getString("sum_id");
                            // 如果指标id相同
                            if (bgtId.equals(sumId)) {
                                // 指标总额
                                String aviamt = jsonObject.getString("aviamt");
                                salaryPaymentRequisitionBack.setAviamt(aviamt);
                                // 可用指标额
                                String canuseamt = jsonObject.getString("canuseamt");
                                salaryPaymentRequisitionBack.setCanuseamt(canuseamt);
                                break;
                            }
                        }
                    }
                }
            }
        }
        return list;
    }


    /**
     * 生成除实发工资外支付申请数据
     * @param payeeColumnList 要生成工资数据的单位
     * @param dataMap
     * @return
     */
    private Map<String, Object> makeOtherSalaryData(List<Map<String, Object>> payeeColumnList, Map<String, Object> dataMap, UserDTO userDTO) {
        Set<String> agencyIds = payeeColumnList.stream().map(map -> map.get("agency_id").toString()).collect(Collectors.toSet());
        agency: for (String agencyId : agencyIds) {
            List<String> columnNames = payeeColumnList.stream()
                    .filter(map -> agencyId.equals(map.get("agency_id")))
                    .map(map-> String.valueOf(map.get("column_name"))).collect(Collectors.toList());
            // 获取不同人员类型的工资数据
            List<Map<String, Object>> salaryList = iGenerateSalaryDataDao.getPersonOtherSalary(agencyId, columnNames);
            if (!StringUtils.isEmpty(salaryList) && salaryList.size() > 0) {
                // 指标额度是否足够
                for (Map<String, Object> map : salaryList) {
                    // 工资类型
                    String meritPayCode = map.get("merit_pay_code").toString();
                    // 根据单位id和人员类别获取工资项和金额
                    for (Map<String, Object> payeeMap: payeeColumnList) {
                        if (agencyId.equals(payeeMap.get("agency_id")) &&
                                meritPayCode.equals(payeeMap.get("person_state"))) {
                            String salaryId = payeeMap.get("salary_base_id").toString();
                            String bankCode = agencyId + "-" + salaryId + meritPayCode;
                            String column = payeeMap.get("column_name").toString();
                            BigDecimal amt = BigDecimal.valueOf(Double.parseDouble(StringUtils.isEmpty(map.get(column)) ? "0.00" : map.get(column).toString()));
                            if(amt.doubleValue()<=0){
                                continue ;
                            }
                            // 检查指标剩余额度是否足够
                            dataMap = checkBgtAmt(agencyId, salaryId, meritPayCode, amt, bankCode, dataMap, userDTO);
                            if ("false".equals(dataMap.get("flag").toString())) {
                                // 单位id
                                dataMap.put("agencyId", agencyId);
                                // 工资项id
                                dataMap.put("salaryId", salaryId);
                                // 人员类型
                                dataMap.put("personType", meritPayCode);
                                break agency;
                            }
                        }
                    }
                }
            }
        }
        return dataMap;
    }

    /**
     * 检查工资项挂接的指标金额是否足够
     * @param agencyId  单位id
     * @param salaryId   工资项id
     * @param meritPayCode  工资类型
     * @param amt 金额合计
     * @param bankCode 银行编码
     * @return
     */
    private Map<String, Object> checkBgtAmt(String agencyId, String salaryId, String meritPayCode, BigDecimal amt, String bankCode, Map<String, Object> dataMap, UserDTO userDTO) {
        // 金额是否充足状态
        boolean isAdequate = false;
        // 指标id剩余金额集合
        List<Map<String, BigDecimal>> canuseAmtList = null;
        // 指标id对应的银行code、已使用金额集合
        List<Map<String, Map<String, BigDecimal>>> bankAmtList = null;
        // 初始化金额集合
        if (!StringUtils.isEmpty(dataMap) && dataMap.size() > 0) {
            canuseAmtList = (List<Map<String, BigDecimal>>) dataMap.get("canuseAmtList");
            bankAmtList = (List<Map<String, Map<String, BigDecimal>>>) dataMap.get("bankAmtList");
        } else {
            canuseAmtList = new ArrayList<>();
            bankAmtList = new ArrayList<>();
        }
        // 根据工资项id和人员类型获取挂接的指标
        List<AgencySalaryPayment> bgtLists = iAgencySalaryPaymentDao.getBgtBySalaryPersonType(salaryId, meritPayCode, agencyId);
        if (!StringUtils.isEmpty(bgtLists) && bgtLists.size() > 0) {
            // 按照扣减顺序排序
            Collections.sort(bgtLists, (o1, o2) -> {
                if (o1.getPayOrder().compareTo(o2.getPayOrder()) > 0) {
                    return 1;
                } else if (o1.getPayOrder().compareTo(o2.getPayOrder()) < 0) {
                    return -1;
                } else {
                    return 0;
                }
            });
            // 获取所有指标id
            List<String> sumIds = bgtLists.stream().filter(bean-> !StringUtils.isEmpty(bean.getBgtId())).collect(Collectors.toList())
                    .stream().map(AgencySalaryPayment::getBgtId).collect(Collectors.toList());
            // 获取之前未获取过的指标id
            sumIds = filterDiffentData(canuseAmtList, sumIds);
            String year=String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
            JSONArray jsonArray = null;
            if (!StringUtils.isEmpty(sumIds) && sumIds.size() > 0) {
                Map<String, Object> query = new HashMap<>();
                StringBuilder sql = new StringBuilder();
                sql.append(" and ");
                sql.append(SysUtils.inSql("sum_id", sumIds));
                sql.append(" and ");
                sql.append(" agency_id = '").append(agencyId).append("'");
                query.put("condition", sql.toString());
                query.put("mof_div_code", userDTO.getProvince());
                query.put("fiscal_year", year);
                query.put("limit", "10000");
                query.put("offset", "1");
                jsonArray =  iCommonService.getPayMent(query, false);
            }
            // 银行金额map
            Map<String, BigDecimal> amtBankMap = null;
            // 指标id下银行金额集合
            Map<String, Map<String,BigDecimal>> bgtIdAmtBankMap = null;
            // 计算预算指标金额
            asp : for (AgencySalaryPayment agencySalaryPayment: bgtLists) {
                bgtIdAmtBankMap = new HashMap<>(1);
                // 银行编码、已使用金额集合
                amtBankMap = new HashMap<>(2);
                boolean history = false;
                String bgtId = agencySalaryPayment.getBgtId();
                // 如果剩余金额集合有数据，先再剩余金额集合中计算
                if (!StringUtils.isEmpty(canuseAmtList) && canuseAmtList.size() > 0) {
                    for (Map<String, BigDecimal> map: canuseAmtList) {
                        if (map.containsKey(bgtId)) {
                            history = true;
                            BigDecimal canuseamt = map.get(bgtId);
                            // 扣除后金额 = 可用金额-总金额
                            BigDecimal deductionamt = canuseamt.subtract(amt);
                            // 指标id对应银行code已使用的金额
                            boolean isHave = calculateBankAmt(bankAmtList, deductionamt, bgtId, bankCode);
                            // 当前指标金额不够，需要扣下一个指标
                            if (deductionamt.compareTo(BigDecimal.ZERO) < 0) {
                                // 计算下一次的总金额
                                amt = amt.subtract(canuseamt);
                                // 如果之前没有该银行数据，则增加新数据
                                if (!isHave) {
                                    amtBankMap.put(bankCode, canuseamt);
                                    bgtIdAmtBankMap.put(bgtId, amtBankMap);
                                    bankAmtList.add(bgtIdAmtBankMap);
                                }
                                // 剩余金额
                                boolean isHaveCanuse = calculateBgtAmt(canuseAmtList, bgtId, BigDecimal.ZERO);
                                if (!isHaveCanuse) {
                                    Map<String, BigDecimal> canuseAmtMap = new HashMap<>(1);
                                    canuseAmtMap.put(bgtId, BigDecimal.ZERO);
                                    canuseAmtList.add(canuseAmtMap);
                                }
                                break;
                            } else {
                                // 如果之前没有该银行数据，则增加新数据
                                if (!isHave) {
                                    amtBankMap.put(bankCode, amt);
                                    bgtIdAmtBankMap.put(bgtId, amtBankMap);
                                    bankAmtList.add(bgtIdAmtBankMap);
                                }
                                // 剩余金额
                                boolean isHaveCanuse = calculateBgtAmt(canuseAmtList, bgtId, deductionamt);
                                if (!isHaveCanuse) {
                                    Map<String, BigDecimal> canuseAmtMap = new HashMap<>(1);
                                    canuseAmtMap.put(bgtId, deductionamt);
                                    canuseAmtList.add(canuseAmtMap);
                                }
                                isAdequate = true;
                                break asp;
                            }
                        }
                    }
                }
                // 遍历指标数据，计算金额
                if (!history) {
                    if (!StringUtils.isEmpty(jsonArray) && jsonArray.size() > 0) {
                        for (int i = 0; i< jsonArray.size(); i++) {
                            // 获取指标数据
                            JSONObject jsonObject = jsonArray.getJSONObject(i);
                            // 指标id
                            String sum_id = jsonObject.getString("sum_id");
                            if (bgtId.equals(sum_id)) {
                                // 指标可用金额
                                BigDecimal canuseamt = jsonObject.getBigDecimal("canuseamt");
                                // 扣除后金额 = 可用金额-总金额
                                BigDecimal deductionamt = canuseamt.subtract(amt);
                                // 指标id对应银行code已使用的金额
                                boolean isHave = calculateBankAmt(bankAmtList, deductionamt, bgtId, bankCode);
                                // 当前指标金额不够，需要扣下一个指标
                                if (deductionamt.compareTo(BigDecimal.ZERO) < 0) {
                                    // 计算下一次的总金额
                                    amt = amt.subtract(canuseamt);
                                    // 如果之前没有该银行数据，则增加新数据
                                    if (!isHave) {
                                        amtBankMap.put(bankCode, canuseamt);
                                        bgtIdAmtBankMap.put(bgtId, amtBankMap);
                                        bankAmtList.add(bgtIdAmtBankMap);
                                    }
                                    // 剩余金额
                                    boolean isHaveCanuse = calculateBgtAmt(canuseAmtList, bgtId, BigDecimal.ZERO);
                                    if (!isHaveCanuse) {
                                        Map<String, BigDecimal> canuseAmtMap = new HashMap<>(1);
                                        canuseAmtMap.put(bgtId, BigDecimal.ZERO);
                                        canuseAmtList.add(canuseAmtMap);
                                    }
                                    break;
                                } else {
                                    // 如果之前没有该银行数据，则增加新数据
                                    if (!isHave) {
                                        amtBankMap.put(bankCode, amt);
                                        bgtIdAmtBankMap.put(bgtId, amtBankMap);
                                        bankAmtList.add(bgtIdAmtBankMap);
                                    }
                                    // 剩余金额
                                    boolean isHaveCanuse = calculateBgtAmt(canuseAmtList, bgtId, deductionamt);
                                    if (!isHaveCanuse) {
                                        Map<String, BigDecimal> canuseAmtMap = new HashMap<>(1);
                                        canuseAmtMap.put(bgtId, deductionamt);
                                        canuseAmtList.add(canuseAmtMap);
                                    }
                                    isAdequate = true;
                                    break asp;
                                }
                            }
                        }
                    }
                }
            }
        } else {
            // TODO 未挂接指标
            isAdequate = false;
        }

        Map<String, Object> map = new HashMap<>(3);
        map.put("flag", isAdequate);
        map.put("canuseAmtList", canuseAmtList);
        map.put("bankAmtList", bankAmtList);
        return map;
    }




    /**
     * 获取不同的bgtId
     * @param map1
     * @param bgtIds
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    private List<String> filterDiffentData(List<Map<String, BigDecimal>> map1, List<String> bgtIds) {
        // 拷贝指标list
        List<String> list = Arrays.asList(new String[bgtIds.size()]);
        Collections.copy(list, bgtIds);
        List newBgtIds = new ArrayList(list);
        for (String bgtId: bgtIds) {
            for (Map<String, BigDecimal> map: map1) {
                if (map.containsKey(bgtId)) {
                    newBgtIds.remove(bgtId);
                    break;
                }
            }
        }
        return newBgtIds;
    }

    /**
     * 计算剩余金额
     * @param canuseAmtList 剩余金额集合
     * @param bgtId 指标id
     * @param amt 剩余金额
     * @return
     */
    private boolean calculateBgtAmt(List<Map<String, BigDecimal>> canuseAmtList, String bgtId, BigDecimal amt) {
        boolean isHaveCanuse = false;
        if (!StringUtils.isEmpty(canuseAmtList) && canuseAmtList.size() > 0) {
            for (Map<String, BigDecimal> canuseAmtMap : canuseAmtList) {
                if (canuseAmtMap.containsKey(bgtId)) {
                    isHaveCanuse = true;
                    canuseAmtMap.put(bgtId, amt);
                }
            }
        }
        return isHaveCanuse;
    }

    /**
     * 计算银行code对应的金额，如果不存在返回
     *
     * @param bankAmtList 银行金额集合
     * @param amt 扣减金额
     * @param bankCode 银行编码
     * @param bgtId 指标id
     * @return
     */
    private boolean calculateBankAmt(List<Map<String, Map<String, BigDecimal>>> bankAmtList, BigDecimal amt, String bgtId, String bankCode) {
        // 历史是否已使用过该银行
        boolean isHave = false;
        if (StringUtils.isEmpty(bankAmtList) && bankAmtList.size() > 0) {
            for (Map<String, Map<String, BigDecimal>> bgtBankAmtMap : bankAmtList) {
                Map<String, BigDecimal> bankAmt = bgtBankAmtMap.get(bgtId);
                // 如果使用过，将值相加
                if (!StringUtils.isEmpty(bankAmt.get(bankCode))) {
                    isHave = true;
                    BigDecimal bankCanuseAmt = bankAmt.get(bankCode);
                    bankAmt.put(bankCode, bankCanuseAmt.add(amt));
                }
            }
        }
        return isHave;
    }

    /**
     * 保存支付回单数据
     * @param jsonArray
     */
    private void savePayBackData(JSONArray jsonArray, UserDTO userDto) {
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            // 修改表状态，并添加模拟值
            String agencyId = jsonObject.getString("agency_id");
            SalaryPaymentRequisitionBack salaryPaymentRequisitionBack = new SalaryPaymentRequisitionBack();
            salaryPaymentRequisitionBack.setId(SysUtils.generateGuid());
            salaryPaymentRequisitionBack.setCreateTime(String.valueOf(DateUtils.getCurrentTimeStamp()));
            salaryPaymentRequisitionBack.setUpdateTime(String.valueOf(DateUtils.getCurrentTimeStamp()));
            salaryPaymentRequisitionBack.setAgencyId(agencyId);
            salaryPaymentRequisitionBack.setAgencyName(jsonObject.getString("agency_name"));
            salaryPaymentRequisitionBack.setPayId(jsonObject.getString("id"));
            salaryPaymentRequisitionBack.setPayAppNo(jsonObject.getString("pay_app_no"));
            salaryPaymentRequisitionBack.setBgtId(jsonObject.getString("bgt_id"));
            salaryPaymentRequisitionBack.setPayAppAmt(jsonObject.getString("pay_app_amt"));
            salaryPaymentRequisitionBack.setFundType(jsonObject.getString("fund_type"));
            salaryPaymentRequisitionBack.setPayeeAcctName(jsonObject.getString("payee_acct_name"));
            salaryPaymentRequisitionBack.setPayeeAcctNo(jsonObject.getString("payee_acct_no"));
            salaryPaymentRequisitionBack.setPayeeAcctBankName(jsonObject.getString("payee_acct_bank_name"));
            salaryPaymentRequisitionBack.setPayType(jsonObject.getString("pay_type"));
            salaryPaymentRequisitionBack.setProCat(jsonObject.getString("pro_cat"));
            salaryPaymentRequisitionBack.setGovBgtEco(jsonObject.getString("gov_bgt_eco"));
            salaryPaymentRequisitionBack.setDepBgtEco(jsonObject.getString("dep_bgt_eco"));
            salaryPaymentRequisitionBack.setPro(jsonObject.getString("pro"));
            salaryPaymentRequisitionBack.setUseName(jsonObject.getString("use_"));
            salaryPaymentRequisitionBack.setExpFunc(jsonObject.getString("exp_func"));
            salaryPaymentRequisitionBack.setMofDivCode(userDto.getProvince());
            salaryPaymentRequisitionBack.setIsDeleted(SystemDictConstant.IS_FALSE);
            iGenerateSalaryDataDao.updatePayData(agencyId, String.valueOf(SystemDictConstant.IS_TRUE));
            iGenerateSalaryDataDao.insertPayBackData(salaryPaymentRequisitionBack);
        }
    }



    /**
     * 生成工资数据异步
     * @param tokenid
     * @param makeSalaryData 要生成工资数据的单位
     * @return
     */
    @Override
    @GlobalTransactional(timeoutMills=300000)//@Transactional(rollbackFor = Exception.class)
    public Map<String,String> makeSalaryDataAsyncRedis(String tokenid, MakeSalaryData makeSalaryData, UserDTO userDto) {
        //校验指标是否单位是否挂接指标和收款户
        String year=String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
        StringBuffer request=new StringBuffer();
        logger.info("生成支付：校验指标挂接情况开始");
        String re= checkPayment(makeSalaryData.getAgencyIds(),userDto);
        List<String> agencyIds=new ArrayList<>();

        if(re!=null&&re.length()>0) {//返回结果不为空且长度大于0则添加到返回结果中
            request.append(re + "\n");
        }
        // 获取已冻结的推送给支付的数据
//        logger.info("生成支付：获取指标冻结信息开始");
//        List<Map<String, Object>> budgetThawpayList=iPayMentLockDao.selectPayMentLock(makeSalaryData.getAgencyIds());
//        //若获取到锁定指标则批量解冻
//        if(!CollectionUtils.isEmpty(budgetThawpayList)) {
//            //批量解冻
//            logger.info("生成支付执行解冻指标执行开始");
//            commonService.batchGocpurbudgetThaw(budgetThawpayList, userDto.getProvince(), year, null);
//            logger.info("生成支付执行解冻指标执行结束");
//        }else{
//            //若没有已锁定，新建对象防止报错
//        }
        List<Map<String, Object>>  payList=new ArrayList<>();
        //检查指标是否足够

        List<Map<String, Object>> falsePayList=new ArrayList<>();
        if(!CollectionUtils.isEmpty(makeSalaryData.getAgencyIds())) {
            logger.info("生成支付：校验指标是否充足开始");
            falsePayList = checkIsEnough(makeSalaryData.getAgencyIds(), userDto, payList,false,tokenid);
            agencyIds.addAll(makeSalaryData.getAgencyIds());//另存走异步接口的所有单位信息
            logger.info("生成支付：校验指标是否充足完成："+payList.toString());
        }

        String uuid=SysUtils.generateGuid();
        if (payList.size() > 0) {//若有可以生成的数据则开始缓存进度
            redisService.put(uuid, 0);
            redisService.put(userDto.getProvince()+"thirteenGenerateSalary", 1);//添加执行控制，避免重复操作
            paymentAsyncService.sentPayMentAsyncForSeate(payList, userDto, makeSalaryData, tokenid, uuid,agencyIds);//事务独立的生成支付方法（单个单位走）
        }
        if(!CollectionUtils.isEmpty(falsePayList)) {
            for (Map reMap : falsePayList) {
                request.append(reMap.get("agency_name").toString() + reMap.get("merit_name").toString() + reMap.get("salary_name").toString() + "指标余额不足！\n");
            }
        }
        Map<String,String> requestMap=new HashMap<>();
        requestMap.put("message",request.toString());
        requestMap.put("guid",uuid);
        return  requestMap;
    }
    /**
     * 校验是否挂接收款户和指标
     * @param agencyIds
     * @param userDto
     * @return
     */
    @Override
    public String checkPayment(List<String> agencyIds, UserDTO userDto) {
        //校验是否单位所有工资类型都挂接了指标Map返回单位名称agency_name和工资类型名称person_type
        StringBuffer result=new StringBuffer();
        List<Map<String,Object>> rmapList=iGenerateSalaryDataDao.isPaymentAllConnectPersonType(agencyIds);
        if(!CollectionUtils.isEmpty(rmapList)){
            for(Map<String,Object> rmap:rmapList){
                result.append(rmap.get("agency_name")).append(":").append(rmap.get("person_type")).append("-").append(rmap.get("salary_base_name")).append(" 未挂接指标\n");
                agencyIds.remove(rmap.get("id"));
            }
        }
        //校验单位是否所有人员类型都挂接了指标工资项收款户
        List<Map<String,Object>> rSalayPersonTypeList=iGenerateSalaryDataDao.isSalaryAllConnectPersonType(agencyIds);
        if(!CollectionUtils.isEmpty(rSalayPersonTypeList)){
            for(Map<String,Object> rmap:rSalayPersonTypeList){
                result.append(rmap.get("agency_name")).append(":").append(rmap.get("person_type")).append(" 未挂接指标工资项收款户\n");
                agencyIds.remove(rmap.get("id"));
            }
        }
        return result.toString();
    }

    @Override
    public List<Map<String, Object>> checkIsEnough(List<String> agencyIds, UserDTO userDto,List<Map<String, Object>> payRequestList,boolean is_agency,String tokenid) {
        String year=String.valueOf(Calendar.getInstance().get(Calendar.YEAR));
        userDto.setYear(Integer.parseInt(year));//取业务年度
        if(!StringUtils.isEmpty(tokenid)) {
            iCommonService.changeYear(tokenid, year);
        }
        //获取所有该区划下挂接指标的工资项
        List<String> columnList = iGenerateSalaryDataDao.getPayeeColumnName(userDto.getProvince());
        // 获取不同人员类型的工资数据
        //agency_id  agency_code agency_name merit_pay_code sala_card_bank  s...
        List<Map<String, Object>> salaryList = iGenerateSalaryDataDao.getPersonOtherSalary(agencyIds, columnList,is_agency);
        // 获取收款户对应的字段
        // column_name salary_base_id person_state agency_id payee_acct_name payee_acct_no payee_acct_bank_name remark
        List<Map<String, Object>> payeeColumnList = iGenerateSalaryDataDao.getPayeeColumnName(agencyIds);
        //获取所有单位挂接指标情况
        List<AgencySalaryPayment> agencyBgtLists = iAgencySalaryPaymentDao.getBgtBySalaryPersonType(agencyIds,userDto);
        //获取所有挂接的指标，查询指标余额用
        List<String> sumIds=agencyBgtLists.stream().map(e -> e.getBgtId()).distinct().collect(Collectors.toList());
        //获取指标可用额度
        //bgtid
        Map<String,BigDecimal> bgtCanuse=  iCommonService.getPayMent(sumIds, userDto);
        //获取工资类型map code-name
        Map<String, Object>  meritMap=iCommonService.queryBaseDataMap("salary_type",userDto.getProvince());
        //获取工资项id-name Map
        Map<String, Object>  salaryBaseMap=iCommonService.querySalaryBaseDataMap(userDto.getProvince());
        //保存各单位各收款户金额
        List<Map<String,Object>> moneyMapList=new ArrayList<>();
        if (!StringUtils.isEmpty(salaryList) && salaryList.size() > 0) {
            // 指标额度是否足够
            for (Map<String, Object> map : salaryList) {
                // 工资类型
                String meritPayCode = map.get("merit_pay_code").toString();
                // 根据单位id和人员类别获取工资项和金额
                for (Map<String, Object> payeeMap: payeeColumnList) {
                    if (map.get("agency_id").equals(payeeMap.get("agency_id")) &&
                            meritPayCode.equals(payeeMap.get("person_state"))) {
                        String salaryId = payeeMap.get("salary_base_id").toString();
                        String bankCode = map.get("agency_id") + "-" + salaryId  + "-" + meritPayCode;
                        String column = payeeMap.get("column_name").toString();
                        String payee_acct_name=payeeMap.get("payee_acct_name").toString();//收款户名称
                        String payee_acct_no=payeeMap.get("payee_acct_no").toString();//收款户账号
                        String payee_acct_bank_name=payeeMap.get("payee_acct_bank_name").toString();//收款户银行
                        Object use_=payeeMap.get("remark");//资金用途
                        BigDecimal amt = BigDecimal.valueOf(Double.parseDouble(StringUtils.isEmpty(map.get(column)) ? "0.00" : map.get(column).toString()));
                        if(amt.doubleValue()<=0){
                            continue ;
                        }
                        Map<String,Object> money=new HashMap<>();
                        money.put("agency_id",map.get("agency_id"));
                        money.put("agency_name",map.get("agency_name"));
                        money.put("merit_name",meritMap.get(meritPayCode));//工资类型名称
                        money.put("salary_name",salaryBaseMap.get(salaryId));//工资项名称
                        money.put("bankCode",bankCode);//键值用单位id 工资项id 和人员工资类型混合键
                        money.put("payee_acct_name",payee_acct_name);
                        money.put("payee_acct_no",payee_acct_no);
                        money.put("payee_acct_bank_name",payee_acct_bank_name);
                        money.put("amt",amt.toString());
                        money.put("use_",use_);
                        moneyMapList.add(money);
                    }
                }
            }
        }
        //todo 计算指标额度是否足够
        List<Map<String,Object>> payList=new ArrayList<>();
        for(Map moneyMap:moneyMapList){
            for(AgencySalaryPayment agencySalaryPayment:agencyBgtLists){
                if(moneyMap.get("bankCode").equals( agencySalaryPayment.getAgencyId() + "-" + agencySalaryPayment.getSalaryId()  + "-" + agencySalaryPayment.getPersonType())){
                    BigDecimal canuse=bgtCanuse.get(agencySalaryPayment.getBgtId());
                    if(canuse==null){
                        continue;
                    }
                    BigDecimal amt=new BigDecimal(moneyMap.get("amt").toString());
                    if(amt.compareTo(new BigDecimal("0.00"))==0){
                        continue;
                    }
                    if(amt.compareTo(canuse) != 1){//如果可用额度大于申请额度
                        bgtCanuse.put(agencySalaryPayment.getBgtId(),canuse.subtract(amt));//指标额度扣减
                        moneyMap.put("amt","0");
                        Map<String,Object> payMap=new HashMap<>();
                        payMap.put("agency_id",moneyMap.get("agency_id"));
                        //payMap.put("bankCode",moneyMap.get("bankCode"));//键值用单位id 工资项id 和人员工资类型混合键
                        payMap.put("bgt_id",agencySalaryPayment.getBgtId());
                        payMap.put("payee_acct_name",moneyMap.get("payee_acct_name"));
                        payMap.put("payee_acct_no",moneyMap.get("payee_acct_no"));
                        payMap.put("payee_acct_bank_name",moneyMap.get("payee_acct_bank_name"));
                        payMap.put("amt",amt);
                        payMap.put("use_",moneyMap.get("use_"));
                        payList.add(payMap);
                    }else{
                        if(canuse.compareTo(new BigDecimal("0.00"))<1){//可用额度小于等于0时继续循环，不进行计算
                            continue;
                        }
                        bgtCanuse.put(agencySalaryPayment.getBgtId(),new BigDecimal("0.00"));//指标额度扣减
                        moneyMap.put("amt",amt.subtract(canuse));
                        Map<String,Object> payMap=new HashMap<>();
                        payMap.put("agency_id",moneyMap.get("agency_id"));
                        //payMap.put("bankCode",moneyMap.get("bankCode"));//键值用单位id 工资项id 和人员工资类型混合键
                        payMap.put("bgt_id",agencySalaryPayment.getBgtId());
                        payMap.put("payee_acct_name",moneyMap.get("payee_acct_name"));
                        payMap.put("payee_acct_no",moneyMap.get("payee_acct_no"));
                        payMap.put("payee_acct_bank_name",moneyMap.get("payee_acct_bank_name"));
                        payMap.put("amt",canuse);
                        payMap.put("use_",moneyMap.get("use_"));
                        payList.add(payMap);
                    }
                }
            }

        }
        List<Map<String,Object>> falseRemovePayList=new ArrayList<>();
        List<Map<String,Object>> falsePayList=new ArrayList<>();
        for(Map moneyMap:moneyMapList){//将原集合中还有金额不为0的过滤出来，不为零表明指标不足
            if(!"0".equals(moneyMap.get("amt"))){//将指标不足的单位从成功集合中剔除
                falseRemovePayList.addAll(payList.stream().filter(map -> moneyMap.get("agency_id").equals(map.get("agency_id"))).collect(Collectors.toList()));
                falsePayList.add(moneyMap);
                agencyIds.remove(moneyMap.get("agency_id"));
            }
        }
        payList.removeAll(falseRemovePayList);//将指标不足的单位从成功集合中剔除
        payRequestList.addAll(payList);//所有成功的添加到传入的List集合中
        return falsePayList;//返回所有失败的信息
    }


    @Override
    public Map<String, Object> checkSalaryData(String tokenid, MakeSalaryData makeSalaryData, UserDTO userDto) {

        Map<String, Object> requestList=new HashMap<>();
        List<Map<String, Object>> falsePayList=new ArrayList<>();
        List<String> agencyIds=new ArrayList<>();
        //校验指标是否单位是否挂接指标和收款户
        logger.info("提前校验：校验指标挂接情况开始");
        StringBuffer result=new StringBuffer();
        List<Map<String,Object>> rmapList=iGenerateSalaryDataDao.isPaymentAllConnectPersonType(makeSalaryData.getAgencyIds());
        if(!CollectionUtils.isEmpty(rmapList)){
            for(Map<String,Object> rmap:rmapList){
                result.append(rmap.get("agency_name")).append(":").append(rmap.get("person_type")).append("-").append(rmap.get("salary_base_name")).append(" 未挂接指标<br/>");
                makeSalaryData.getAgencyIds().remove(rmap.get("id"));
                agencyIds.add(rmap.get("id").toString());
            }
        }
        //校验单位是否所有人员类型都挂接了指标工资项收款户
        List<Map<String,Object>> rSalayPersonTypeList=iGenerateSalaryDataDao.isSalaryAllConnectPersonType(makeSalaryData.getAgencyIds());
        if(!CollectionUtils.isEmpty(rSalayPersonTypeList)){
            for(Map<String,Object> rmap:rSalayPersonTypeList){
                result.append(rmap.get("agency_name")).append(":").append(rmap.get("person_type")).append(" 未挂接指标工资项收款户<br/>");
                makeSalaryData.getAgencyIds().remove(rmap.get("id"));
                agencyIds.add(rmap.get("id").toString());
            }
        }


        // 获取已冻结的推送给支付的数据
        logger.info("提前校验：获取指标冻结信息开始");
        List<Map<String, Object>> budgetThawpayList=iPayMentLockDao.selectPayMentLock(makeSalaryData.getAgencyIds());
        //若获取到锁定指标则批量解冻
        if(!CollectionUtils.isEmpty(budgetThawpayList)) {
            for (Map<String, Object> map : budgetThawpayList) {
                //则将获取到的已锁定单位从List中移除
                makeSalaryData.getAgencyIds().remove(map.get("agency_id"));
            }
        }
        List<Map<String, Object>>  payList=new ArrayList<>();
        //检查指标是否足够
        if(!CollectionUtils.isEmpty(makeSalaryData.getAgencyIds())) {
            logger.info("提前校验：校验指标是否充足");
            falsePayList = checkIsEnough(makeSalaryData.getAgencyIds(), userDto, payList,false,null);
        }
        if(!CollectionUtils.isEmpty(falsePayList)) {
            for (Map reMap : falsePayList) {
                result.append(reMap.get("agency_name").toString() + reMap.get("merit_name").toString() + reMap.get("salary_name").toString() + "指标余额不足！<br/>");
                agencyIds.add(reMap.get("agency_id").toString());
            }
        }
        requestList.put("request",result.toString());
        requestList.put("data",agencyIds);

        return requestList;
    }

}
